#include "SemanticNodeMethod.h"

#include "SemanticNodeMethodBody.h"
#include "../errors_warnings.h"

SemanticNodeMethod::SemanticNodeMethod (SyntaxTreeNode *syntaxNode, SemanticNode *parent) : SemanticNode(parent) {

	parseMods(syntaxNode->Nodes->GetData(0));

	switch (syntaxNode->Production) {
	case Gr_MethodDefinition__MethodMods_StartProcess_DataType_NAME_spLPar_Parameters_spRPar_MethodBodyDecl:
		parseStartProcess(syntaxNode->Nodes->GetData(1));
		returnType = new ValueType(syntaxNode->Nodes->GetData(2));
		LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode->Nodes->GetData(3)->LexUnitID);
		name = CompilerData->Units->GetLexicUnitString(&lu);
		arguments = OurSemanticAnalyzer::analyzeNodeArgument(syntaxNode->Nodes->GetData(5), parent);
		body = new SemanticNodeMethodBody(syntaxNode->Nodes->GetData(7), this);
		break;
	case Gr_MethodDefinition__MethodMods_numeric_NumericMod_DataType_NAME_spLPar_Parameters_spRPar_spLCBrac_InfBegin_ValuePairs_InfEnd_spRCBrac:
		//TODO da li ova produkcija postoji ???
		returnType->setType(syntaxNode->Nodes->GetData(3));
		LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode->Nodes->GetData(4)->LexUnitID);
		name = CompilerData->Units->GetLexicUnitString(&lu);
		arguments = OurSemanticAnalyzer::analyzeNodeArgument(syntaxNode->Nodes->GetData(6), parent);
		//TODO
		break;
	default:
		//ne bi se trebalo dogoditi
		break;
	}
}

void SemanticNodeMethod::parseMods (SyntaxTreeNode* modsNode) {
	modAbstract = false; modFinal = false; modOverride = false;
	modPrivate = false; modProtected = false; modPublic = false;
	modStatic = false; modVirtual = false;
	for (int i = 0; i < modsNode->Nodes->GetCount(); ++i) {
		switch (modsNode->Nodes->GetData(i)->Production) {
		case Gr_MethodMod__abstract:
			if (modAbstract || modFinal || modOverride || modStatic || modVirtual) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			modAbstract = true;
			break;
		case Gr_MethodMod__override:
			if (modAbstract || modFinal || modOverride || modStatic || modVirtual) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			modOverride = true;
			break;
		case Gr_MethodMod__static:
			if (modAbstract || modFinal || modOverride || modStatic || modVirtual) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			modStatic = true;
			break;
		case Gr_MethodMod__virtual:
			if (modAbstract || modFinal || modOverride || modStatic || modVirtual) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			modVirtual = true;
			break;
		case Gr_MethodMod__final:
			if (modAbstract || modFinal || modOverride || modStatic || modVirtual) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			modFinal = true;
			break;
		case Gr_MethodMod__private:
			if (modPrivate || modPublic || modProtected) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
				break;
			}
			modPrivate = true;
			break;
		case Gr_MethodMod__protected:
			if (modPrivate || modPublic || modProtected) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
				break;
			}
			modProtected = true;
			break;
		case Gr_MethodMod__public:
			if (modPrivate || modPublic || modProtected) {
				LexicUnit lu = CompilerData->Units->GetLexicUnit(modsNode->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
				break;
			}
			modPublic = true;
			break;
		default:
			// ako je sintaksa dobro napravljena ovo se ne bi smjelo dogodit
			break;
		}
	}
	if (!modProtected && !modPublic) modPrivate = true;
}

void SemanticNodeMethod::parseStartProcess (SyntaxTreeNode* startProcessNode) {
	switch (startProcessNode->Nodes->GetCount()) {
	case 0:
		start = false;
		process = false;
		break;
	case 1:
		start = false;
		process = true;
		break;
	case 2:
		start = true;
		process = true;
		break;
	default:
		//TODO ne bi se trebalo dogoditi ako je sintaksno stablo ok
		break;
	}
}

















std::string SemanticNodeMethod::toDebugString(int tab) {
	std::ostringstream ss;
	for (int i = 0; i < tab; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "method " << name << " {" << std::endl;

	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
		ss << "Mods: { ";
	if (modPrivate) ss << "private ";
	if (modProtected) ss << "protected ";
	if (modPublic) ss << "public ";
	if (modAbstract) ss << "abstract ";
	if (modFinal) ss << "final ";
	if (modOverride) ss << "override ";
	if (modStatic) ss << "static ";
	if (modVirtual) ss << "virtual ";
	if (start) ss << "start ";
	if (process) ss << "process ";
	ss << "}" << std::endl;

	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
		ss << "Arguments: { " << std::endl;
	for (std::vector<SemanticNodeExpression*>::iterator i = arguments.begin(); i != arguments.end(); ++i)
		ss << (*i)->toDebugString(tab + 2);
	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "}" << std::endl;

	ss  << body->toDebugString(tab + 1);

	for (int i = 0; i < tab; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "}" << std::endl;

	return ss.str();
}




